//
// Created on 2024/2/27.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef OHOS_INPUTHANDLER_H
#define OHOS_INPUTHANDLER_H

#include <ace/xcomponent/native_interface_xcomponent.h>
#include <list>
#include "napi/common/OhosLog.h"

typedef struct _TouchPoint{
    float _x;
    float _y;
    int64_t _timeStamp;
    
    _TouchPoint(float x, float y, int64_t timeStamp){
        _x = x;
        _y = y;
        _timeStamp = timeStamp;
    }
    
    _TouchPoint(const _TouchPoint &touchPoint){
        _x = touchPoint._x;
        _y = touchPoint._y;
        _timeStamp = touchPoint._timeStamp;
    }
} TouchPoint;

class TouchTracker{
public:
    static int nextTouchId;
    TouchTracker(int32_t _pointerId): startPoint(nullptr), lastPoint(nullptr) {
        nextTouchId++;
        touchId = nextTouchId;
        pointerId = _pointerId;
    }
    
    ~TouchTracker() {
        delete startPoint;
        delete lastPoint;
    }
    
    void update(TouchPoint* touchPoint, OH_NativeXComponent_TouchEventType type){
        delete this->lastPoint;
        this->lastPoint = touchPoint;
        this->type = type;
    }

    OH_NativeXComponent_TouchEventType type;

    /** Unique identifier of a finger. */
    int32_t touchId;
    
    int32_t pointerId;
    
    TouchPoint* startPoint;
    
    TouchPoint* lastPoint;
    
};



class TapTracker {
public:
    TapTracker() : tapPoint(nullptr), startPoint(nullptr), lastPoint(nullptr), lastTapTimestamp(0), tapCount(0) {}

    ~TapTracker() {
        delete tapPoint;
        delete startPoint;
        delete lastPoint;
    }

    void reset() {
        if (tapPoint) {
            delete tapPoint;
            tapPoint = nullptr;
        }
        if (startPoint) {
            delete startPoint;
            startPoint = nullptr;
        }
        if (lastPoint) {
            delete lastPoint;
            lastPoint = nullptr;
        }
        
        lastTapTimestamp = 0;
        tapCount = 0;
    }

    static bool areCoordinatesWithinTapBounds(TouchPoint *point1, TouchPoint *point2){
        if ((point1 == nullptr) || (point2 == nullptr)) {
            return false;
        }
        float deltaX = abs(point2->_x - point1->_x);
        float deltaY = abs(point2->_y - point1->_y);
        return ((deltaX <= 40.0f) && (deltaY <= 40.0f));
    }
    
    void update(TouchPoint *touchPoint, OH_NativeXComponent_TouchEventType type) {
        if(tapPoint) {
            delete tapPoint;
            tapPoint = nullptr;
        }
        
        if(type == OH_NativeXComponent_TouchEventType::OH_NATIVEXCOMPONENT_DOWN){
            if (startPoint == nullptr) {
                startPoint = new TouchPoint(*touchPoint);
            }
            
            if(lastPoint){
                delete lastPoint;
            }
            lastPoint = new TouchPoint(*touchPoint);
            
            if( ! areCoordinatesWithinTapBounds(startPoint, lastPoint) ) {
                tapCount = 0;
                delete startPoint;
                startPoint = new TouchPoint(*lastPoint);
            }
        }
        else if(startPoint && (type == OH_NativeXComponent_TouchEventType::OH_NATIVEXCOMPONENT_UP)) {
            if ( areCoordinatesWithinTapBounds(touchPoint, lastPoint) ) {
                if(touchPoint->_timeStamp - lastTapTimestamp > 500) {
                    tapCount = 1;
                }
                else if(tapCount < INT32_MAX) {
                    tapCount++;
                }
                
                lastTapTimestamp = touchPoint->_timeStamp;
                tapPoint = new TouchPoint(*touchPoint);
                
                delete lastPoint;
                lastPoint = nullptr;
            }
        }
        
        
    }

    void update(OH_NativeXComponent_TouchEvent* touchEvent) {
        if(touchEvent->numPoints > 1){
            reset();
        }

        TouchPoint* point = new TouchPoint(touchEvent->x, touchEvent->y, touchEvent->timeStamp);
        update(point, touchEvent->type);
        delete point;
    }

    OH_NativeXComponent_TouchEventType type;

    int64_t lastTapTimestamp;
    
    int tapCount;
    /** Unique identifier of a finger. */
    int32_t touchId;
    
    TouchPoint *tapPoint;

    TouchPoint *startPoint;

    TouchPoint *lastPoint;
};

class InputHandler {
public:
    static TouchTracker *getTouchById(int32_t touchId);
    static TapTracker *getTapById(int32_t touchId);
//     static void removeById(int32_t touchId);

    static void handleTouchBegin(OH_NativeXComponent_TouchEvent* touchEvent);
    static void handleTouchEnd(OH_NativeXComponent_TouchEvent *touchEvent);
    static void handleTouchMove(OH_NativeXComponent_TouchEvent *touchEvent);
    static void handleTouchCancel(OH_NativeXComponent_TouchEvent *touchEvent);
    
//     static void handleMultiTouchEnd(OH_NativeXComponent_TouchEvent *touchEvent);
    
    static void handleTapEvent(OH_NativeXComponent_TouchEvent *touchEvent);
private:
    static std::list<TouchTracker *> touchTrackers;
    static std::list<TapTracker *> tapTrackers;
};

#endif //OHOS_INPUTHANDLER_H
